feat(approvals): declare full decision/continuity action set + wire revise/resubmit routes#3300
Merged
Merged
Conversation
…evise/resubmit routes
Backend half of retiring the approvals inbox's hand-written buttons
(objectui#2678 P2-4 follow-up). The console's generic action runtime already
renders `sys_approval_request`'s declared actions anywhere the object is
surfaced; this completes the declared set so the inbox no longer needs a
bespoke button per capability.
New declared actions on sys_approval_request (all `type:'api'`, POST, {id}-
interpolated, refreshAfter):
- approval_send_back → /revise (approver; status==pending)
- approval_request_info → /request-info (approver; comment required)
- approval_remind → /remind (submitter-gated)
- approval_recall → /recall (submitter-gated; pending|returned)
- approval_resubmit → /resubmit (submitter-gated; returned)
Submitter-only levers gate on `record.submitter_id == ctx.user.id` (the
console exposes the current user in the predicate scope); approver actions
gate only on `record.status == "pending"` and defer who-can-act to the
service, matching the existing approve/reject precedent.
approval_reassign's `to` param becomes field-backed on `submitter_id` so the
dialog resolves its `sys_user` lookup config and renders a real user picker
(keyed as `to`), replacing the free-text user-id box.
Also registers the missing `/revise` and `/resubmit` REST routes: the console
has been POSTing to them for send-back/resubmit (ADR-0044) but rest-server
never wired them, so both 404'd. They now dispatch to the existing
ApprovalService.sendBack / resubmit with the standard approval error mapping.
Contract test pins the action set, that every target hits a registered route
verb, and the submitter-vs-approver gating.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016ypkQikZ55oWUHUnMebwXA
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
📓 Docs Drift CheckThis PR changes 2 package(s): 10 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
os-zhuang
marked this pull request as ready for review
July 19, 2026 16:58
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Backend half of retiring the approvals inbox's hand-written buttons (objectui#2678 P2-4 follow-up). The console's generic action runtime already renders
sys_approval_request's server-declared actions anywhere the object is surfaced (the inbox'sDeclaredActionsBarincluded); this completes the declared set so the inbox no longer needs a bespoke button per capability.What
New declared actions on
sys_approval_request— alltype:'api',POST,{id}-interpolated,refreshAfter:approval_send_back/revisestatus == pendingapproval_request_info/request-infostatus == pending(comment required)approval_remind/remindstatus == pending && submitter_id == ctx.user.idapproval_recall/recall(pending || returned) && submitter_id == ctx.user.idapproval_resubmit/resubmitstatus == returned && submitter_id == ctx.user.idrecord.submitter_id == ctx.user.id— the console exposes the current user in the predicate scope. Approver actions gate only onrecord.status == "pending"and defer who-can-act to the service, matching the existingapprove/rejectprecedent (the service is the authority;visibleonly trims the obvious non-pending case).approval_reassign'stoparam becomes field-backed onsubmitter_id, so the dialog resolves itssys_userlookup config and renders a real user picker (keyed asto) instead of a free-text user-id box.Registers the missing
/reviseand/resubmitREST routes. The console has been POSTing to these for send-back / resubmit (ADR-0044) since those buttons shipped, butrest-servernever wired them — so both returned 404. They now dispatch to the existingApprovalService.sendBack/resubmitwith the standard approval error mapping (VALIDATION_FAILED→400,INVALID_STATE→409,FORBIDDEN→403,REQUEST_NOT_FOUND→404). This fixes a pre-existing gap independently of the SDUI work.Why
This is the structural payoff from the #2678 audit: approval capabilities ship as backend metadata, and any surface that mounts
DeclaredActionsBarrenders them with zero per-action UI code. The objectui follow-up retires the inbox's hardcoded send-back / request-info / reassign / remind / recall / resubmit buttons on top of this.Verification
plugin-approvalssuite green (143 tests), incl. a new contract test pinning the action set, that everytype:'api'target maps to a registered approvals route verb, and the submitter-vs-approver gating.restbuilds clean (route additions typecheck).POST /revisereturned 404 before this change while/recallreturned 401 (auth) — i.e. the route was genuinely absent.Refs
objectui#2678 (P2-4) · ADR-0044 (send-back/resubmit) · ADR-0019 (approval-as-flow-node)
🤖 Generated with Claude Code
Generated by Claude Code